﻿<html xmlns:MSHelp="http://msdn.microsoft.com/mshelp" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xanx="http://schemas.microsoft.com/developer/xanx/2005"><head><META http-equiv="Content-Type" content="text/html; charset=utf-8"><META NAME="save" CONTENT="history"><title>Marblets Starter Kit</title>
<style><!--
/***********************************************************
 *             SCRIPT-SUPPORTING STYLES
 ***********************************************************/

/* Defines the userData cache persistence mechanism. */
.userDataStyle
{
	behavior: url(#default#userData);
}

/* Used to save the scroll bar position when navigating away from a page. */
div.saveHistory
{
	behavior: url(#default#saveHistory);
}

/* Formats the expand/collapse images for all collapsible regions. */
img.toggle
{
	border: 0;
	margin-right: 5;
}

/* Formats the Language filter drop-down image. */
img#languageFilterImage
{
	border: 0;
	margin-left: 0;
	vertical-align: middle;
}

/* Formats the Members Options filter drop-down image. */
img#membersOptionsFilterImage
{
	border: 0;
	margin-left: 0;
	vertical-align: middle;
}

/* Formats the Collapse All/Expand All images. */
img#toggleAllImage
{
	margin-left: 0;
	vertical-align: middle;
}

/* Supports XLinks */
MSHelp\:link
{
 	text-decoration: underline;
	color: #0000ff; 
	hoverColor: #3366ff;
	filterString: ;
}


body
	{
	background:	#FFFFFF;
	color: #000000;
	font-family:	Verdana;
	font-size: medium;
	font-style: normal;
	font-weight: normal;
	margin-top:	0;
	margin-bottom:	0;
	margin-left:	0;
	margin-right:	0;
	width:	100%;
	/*font-size: 110%;*/
	}

div.section
	{
	margin-left: 15px;
	}

div.hxnx5
	{
	margin-left: 1.5em;
	}

/* Font for all headings */	
h1, h2, h3, h4, h5, h6
	{
	font-family: Verdana, Arial, Helvetica, sans-serif;
	margin-top: 18;
	margin-bottom: 8; 
	font-weight: bold;
	}
h1
	{
	font-size: 130%;
	color: #003399;
	}
div#scrollyes h1 /* Changes font size for full-scrolling topic */
	{
	font-size: 150%;
	}
h2
	{
	font-size: 125%;
	}
h3
	{
	font-size: 115%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h4
	{
	font-size: 115%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h5
	{
	font-size: 100%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h6
	{
	font-size: 100%;
	margin-top: 9;
	margin-bottom: 4; 
	}

ul p, ol p, dl p
	{
	margin-left: 0em;
	}

p
	{
	margin-top: .6em;
	margin-bottom: .6em;
	}
	
td p
	{
	margin-top: 0.0em;
	margin-bottom: 0.6em;
	}

dd p
	{
	margin-top: 0.0em;
	margin-bottom: 0.6em;
	}

.image
	{
	text-align: center;
	}

dl
	{
	margin-top: 0em; 
	margin-bottom: 1.3em;
	}

dd
	{
	margin-bottom: 0em;
	margin-left: 0;
	}

dl.glossary dd 
{
	margin-bottom: 0em;  
	margin-left: 1.5em; 
}

dt
	{
	margin-top: .6em;
	margin-bottom: 1;
	}

ul, ol
	{
	margin-top: 0.6em;
	margin-bottom: 0.6em; 	
	}
	
ol
	{
	margin-left: 2.5em; 
	
	}	
	
ul
	{
	list-style-type: disc; 
	margin-left: 1.9em; 
	}

li
	{
	margin-bottom: 0.4em;
	}

ul ol, ol ol
	{
	list-style-type: lower-alpha;
	}

pre
	{
	margin-top: .6em;
	margin-bottom: .6em; 
	}

pre
	{
	font: 105% Lucida, mono; 
	color: #000066;
	}

code
{
	font-family: Monospace, Courier New, Courier;
	font-size: 105%;
	color:	#000066;
}

table.userdata td 
	{
	background: #ffffff;
	background-color: #F5F5F5;
	border-color: #ffffff;
	border: none;
	}	
table.clsWarning
	{
	background: #ffffff;
	padding: 0px;
	margin: 0px;
	border: none;
	}
table.clsWarning td
	{
	padding: 0px;
	margin: 0px;
	background: #ffffff;
	vertical-align: middle;
	font-size: 70%;
	}

div#mainSection table
	{
	width: 98%;
	background: #ffffff;
	margin-top: 5px;
	margin-bottom: 5px;
	}

div#mainSection table th
	{ 
	padding: 5px 6px;
	background: #EFEFF7;
	text-align: left;
	font-size: 70%;
	vertical-align: bottom;
	border-bottom: 1px solid #C8CDDE;
	}
div#mainSection table td
	{ 
	padding: 5px 5px;
	background: #F7F7FF;
	vertical-align: top;
	font-size: 70%;
	border-bottom: 1px solid #D5D5D3;
	}

div#syntaxCodeBlocks table th
	{
	padding: 1px 6px;
	color: #000066;
	}

div#syntaxCodeBlocks table td
	{
	padding: 1px 5px;
	}

/* Applies to the running header text in the first row of the upper table in the
   non-scrolling header region. */
span#runningHeaderText
{
	color: #003399;
	font-size: 90%;
	padding-left: 13;
}

/* Applies to the topic title in the second row of the upper table in the
   non-scrolling header region. */
span#nsrTitle
{
	color: #003399;
	font-size: 120%;
	font-weight: 600;
	padding-left: 13;
}

/* Applies to everything below the non-scrolling header region. */
div#mainSection
{
	font-size: 70%;
	width: 100%;
}

/* Applies to everything below the non-scrolling header region, minus the footer. */
div#mainBody
{
	font-size: 90%;
	margin-left: 15;
	margin-top: 10;
	padding-bottom: 20;
}

/* Adds right padding for all blocks in mainBody */
div#mainBody p, div#mainBody ol, div#mainBody ul, div#mainBody dl
{
	padding-right: 5;
}

div#mainBody div.alert, div#mainBody div.code, div#mainBody div.tableSection
{
	width:98.9%;
}

div.alert p, div.code p
{
	margin-top:5;
	margin-bottom:8;
}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Begin Note Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
div#mainSection div.alert table
{
	border: 0;
}

div#mainSection div.alert table th
{
	padding-top: 0;
	padding-bottom: 0;
	padding-left: 5;
	padding-right: 5;
}

div#mainSection div.alert table td
{
	padding-left: 5;
	padding-right: 5;
}

img.note
{
	border: 0;
	margin-left: 0;
	margin-right: 3;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - End Note Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Begin Non-scrolling Header Region Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* Applies to the entire non-scrolling header region. */
div#header
{
	background-color: #D4DFFF;
	padding-top:	0;
	padding-bottom:	0;
	padding-left:	0;
	padding-right:	0;
	width:	100%;
}

/* Applies to both tables in the non-scrolling header region. */
div#header table
{
	margin-top:	0;
	margin-bottom: 0;
	border-bottom-color: #C8CDDE;
	border-bottom-style: solid;
	border-bottom-width: 1;
	background: #D4DFFF;
	width:	100%;
}

/* Applies to cells in both tables in the non-scrolling header region. */
div#header table td
{
	color: #0000FF;
	font-size: 70%;
	padding-right: 20;
	padding-top: 1;
	padding-bottom: 1;
	border: none;
	background: #D4DFFF;
}

/* Applies to the last row in the upper table of the non-scrolling header region. Text 
   in this row includes See Also, Constructors, Methods, and Properties. */
div#header table tr#headerTableRow3 td
{
	padding-bottom: 2;
	padding-top: 5;
	padding-left: 15;
}

/* Applies to the lower table in the non-scrolling header region. Text in this table
   includes Collapse All/Expand All, Language Filter, and Members Options. */
div#header table#bottomTable
{
	border-top-color: #FFFFFF;
	border-top-style: solid;
	border-top-width: 1;
	text-align: left;
	padding-left: 15;
}


blockquote
	{
	margin-left: 3.8em;
	margin-right: 3.8em;
	margin-top: .6em;
	margin-bottom: .6em;
	}

sup
	{
	text-decoration: none;
	font-size: smaller; 
	}

a:link
	{
	color: #0000FF;
/*    font-weight: bold */
	}
	
a:visited
	{
	color: #0000AA;
/*    font-weight: bold	*/
	}
	
a:hover
	{
	color: #3366FF;
/*    font-weight: bold */
	}
	
.label
	{
	font-weight: bold; 
	margin-top: 1em;
	margin-left: -26px;
	}
	
.tl
	{
	margin-bottom: .75em; 
	}
	
.atl
	{
	padding-left: 1.5em;
	padding-bottom: .75em; 
	}
	
.cfe
	{
	font-weight: bold; 
	}
	
.mini
	{
	font-size: smaller;
	}
	
.dt
	{
	margin-bottom: -.6em; 
	}
	
.indent
	{
	margin-left: 1.9em; 
	margin-right: 1.9em;
	}

.product
	{
	text-align: right;
	color: #333333;
	font-size: smaller;
	font-style: italic;
	}

.buttonbarshade
	{
	position: relative;
	margin: 0;
	left: 0px;
	top: 2;
	width: 50%;
	height: 40px;
	}

.buttonbartable
	{
	position: absolute;
	margin: 0;
	padding:0;
	border:0;
	left:0px;
	top: 2;
	width: 100%;
	height: 40px;
	}

/* background color, font for header */ 
table.buttonbartable td, table.buttonbarshade td
	{
	background: #ffffff; /*#5177B8; #80C615;*/
	border-left: 0px solid #80C615;
	margin: 0;
	padding: 0px 0px 0px 0px;
	font-family: Impact, sans-serif;
	font-size: 14pt;
	}

table.buttonbartable td.button1
	{
	background: #5177B8; /*#80C615;*/;
	padding: 0;
	font-weight: bold;
	text-align: center;
	cursor: hand;
	}

table.buttonbartable td.button2
	{
	background: #5177B8; /*#80C615;*/;
	font-weight: bold;
	text-align: center;
	}

table.buttonbartable td.button3
	{
	background: #5177B8; /*#80C615;*/;
	font-weight: bold;
	text-align: center;
	}

table.buttonbartable td.runninghead
	{
	padding-left: 0px;
	font-style: italic;
	text-align: left;
	}

.version
	{
	text-align: left;
	color: #000000;
	margin-top: 3em;
	margin-left: -26px;
	font-size: smaller;
	font-style: italic;
	}

.lang, .ilang
	{
	color: #0000ff;
	font: normal 7pt Arial, Helvetica, sans-serif;
	}

div.langMenu
	{
	position: absolute;
	z-index: 1;
	width: 96pt;
	padding: 8pt;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

div.langMenu ul
	{
	padding-left: 2em;
	margin-left: 0;
	}

div.filtered
	{
	margin: 4pt 0 8pt -26px;
	padding: 4px 4px 8px 26px;
	width: 100%;
	border: 2px solid #aaaacc;
	background: #ffffff;
	}

div.filtered2
	{
	margin: 4pt 0 8pt -26px;
	padding: 4px 4px 8px 26px;
	width: 100%;
	border: none;
	background: #ffffff;
	}

div.filtered h1, div.filtered h2, div.filtered h3, div.filtered h4
	{
	margin-left: -22px;
	}

div.filtered span.lang
	{
	position: relative;
	left: -22px;
	}

div.reftip
	{
	position: absolute;
	z-index: 1;
	padding: 8pt;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

a.synParam
	{
	color: #0000FF;
	/*color: #3F7800;*/ 	
	/*color: #8DC54F;*/
	text-decoration: none;
    font-weight: normal;
	}

a.synParam:hover
	{
	text-decoration: underline;
    font-weight: normal;
	}

div.sapop
	{
	position: absolute;
	z-index: 1;
	left: 26px;
	width: 100%;
	padding: 10px 10px 10px 36px;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

div.footer
	{
	width: 100%;
	border: none;
	background: #ffffff;
	margin-top: 18pt;
	padding-bottom: 12pt;
	color: #0000FF;
	/*color: #228B22; */
	text-align: center;
	font-size: 76%;
	}

div.preliminary
	{
	margin-top: 8pt;
	padding-bottom: 12pt;
	color: #A0A0A0;
	}

/* A procedure section. eg. 'To create a file', 'To add a value' */
div.proc
    {
	margin-left: 0.5em; 
    }
     
/* The title of a 'procedure' section. */
div.proc h3
    {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-weight: bold;
	font-size: 115%;
	margin-top: 1em;
	margin-bottom: 0.4em;
	margin-left: -0.5em; 
	color: #003399;
    }

div.proc ul
    {
    margin-left: 1.5em;
    }

div.proc ol
    {
    margin-left: 2.0em;
    }
      
.note
	{
	margin-left: 14pt;
	margin-right: 12pt;
	}

.indent1
	{
	margin-left: 12pt;
	}

.indent2
	{
	margin-left: 24pt;
	}

.indent3
	{
	margin-left: 36pt;
	}

p.proch
	{
	padding-left: 16px;
	}

p.proch img
	{
	position: relative; 
	vertical-align: top;
	left: -18px; 
	margin-right: -14px; 
	margin-bottom: -18px;
	}
	
div.clsPlatSpec
{
	background-color:#FFF8DC;
	border-style:solid;
	border-width:1pt 0pt 0pt 1pt;
	border-color:#ffE4C4;
	margin-top:0.6em;
	width:100%;
}


/* Applies to the language labels in the Language Filter drop-down list. */
.languageFilter
{
	color:	#0000FF;
	cursor:hand;
	text-decoration:underline;
	padding-bottom:4;
}

/* Dropdown areas */

#languageSpan {
	position: absolute;
	visibility: hidden;
	border-style: solid;
	border-width: 1px;
	border-color: #C8CDDE;
	background: #d4dfff;
	padding: 4px;
	font-size: 70%;
}

#membersOptionsSpan {
	position: absolute;
	visibility: hidden;
	border-style: solid;
	border-width: 1px;
	border-color: #C8CDDE;
	background: #d4dfff;
	padding: 4px;
	font-size: 70%;
}
--></style>

<xml>
<MSHelp:TOCTitle Title="Marblets Starter Kit" />
<MSHelp:RLTitle Title="Marblets Starter Kit" />
<MSHelp:Keyword Index="A" Term="15fa81fb-d22c-bffe-81ff-d1b4ba4a4a16" />
<MSHelp:Keyword Index="K" Term="Marblets Starter Kit" />
<MSHelp:Attr Name="ProjType" Value="LocalProj" />
<MSHelp:Attr Name="ProjType" Value="XNA_20" />
<MSHelp:Attr Name="DocSet" Value="XNA" />
<MSHelp:Attr Name="DocSet" Value="ExpressLibVS" />
<MSHelp:Attr Name="DocSet" Value="C#" />
<MSHelp:Attr Name="Locale" Value="en-us" />
<MSHelp:Attr Name="AssetID" Value="15fa81fb-d22c-bffe-81ff-d1b4ba4a4a16" />
<MSHelp:Attr Name="TopicType" Value="kbOrient" />
</xml>
</head><body><div id="mainSection"><div id="mainBody">
  <h1>Marblets Starter Kit</h1>
  
  <p>This topic contains the following sections.</p>
  <ul><li><a href="#ID2EP">Introduction to Marblets</a></li><li><a href="#ID2EBB">Goals</a></li><li><a href="#ID2EWB">Getting Started</a></li><li><a href="#ID2EFD">Marblets Controls</a></li><li><a href="#ID2EDG">Code Walkthrough</a></li><li><a href="#extending">Extending Marblets</a></li></ul>

  <a name="ID2EP"></a><h1 class="heading">Introduction to Marblets</h1><div id="ID2EP" class="hxnx1">
    
    <p>The Marblets Starter Kit is a complete XNA Game Studio game. The project comes ready to compile and run, and it's easy to customize with a little bit of C# programming. The <a href="#extending">Extending Marblets</a> section contains a list of some customizations you might make. You are also free to use the source code as the basis for your own XNA Game Studio game projects, and to share your work with others.</p>

    <p>Marblets is a puzzle-style game that challenges you to eliminate groups of same-colored bubbles. The more bubbles you eliminate at one time, the higher your score. This starter kit version offers only a few game modes, providing ample opportunity to add your own unique game types and modes.</p>
  </div>
  <a name="ID2EBB"></a><h1 class="heading">Goals</h1><div id="ID2EBB" class="hxnx1">
    
    <p>This starter kit provides a complete XNA Game Studio game, including source code and game content such as models, textures, and sounds.  This starter kit documentation describes the architecture and content of Marblets, and suggests interesting customizations you can make.  The Marblets starter kit demonstrates the following:</p>
    <ul>
      <li>Simple game development techniques</li>
      <li>Simple game component usage</li>
      <li>Simple 2D animation without custom shaders</li>
      <li>Sharing code from the Spacewar Starter Kit, to improve learning speed</li>
    </ul>
  </div>

  <a name="ID2EWB"></a><h1 class="heading">Getting Started</h1><div id="ID2EWB" class="hxnx1">
    
    <p>Follow these procedures to get started.</p>
    <div class="proc"><h3 class="subHeading">To build and run the Marblets project</h3><div class="subSection">
      
      <ul>
        <li>
          <p>Press F5, or, on the <b>Debug</b> menu, click <b>Start Debugging</b>.</p>
        </li>
      </ul>
      <p>The project will build and then run within the debugger.</p>
    </div></div>

    <div class="proc"><h3 class="subHeading">To build the project without running it</h3><div class="subSection">
      
      <ul>
        <li>
          <p>Press F6, or, on the <b>Build</b> menu, click <b>Build Solution</b>.</p>
        </li>
      </ul>
      <p>The project will build without running.</p>
    </div></div>
  </div>

  <a name="ID2EFD"></a><h1 class="heading">Marblets Controls</h1><div id="ID2EFD" class="hxnx1">
    
    <p>You can use a keyboard or Xbox 360 Controller to play Marblets.  The controls are mapped as follows:</p>
    <table>
      <tr>
        <th>Action</th>
        <th>Controller</th>
        <th>Keyboard</th>
      </tr>
      <tr>
        <td>Start the game.</td>
        <td>
          <b>A</b>
        </td>
        <td>
          <b>A</b>
        </td>
      </tr>
      <tr>
        <td>Exit the game.</td>
        <td>
          <b>BACK</b>
        </td>
        <td>ESC</td>
      </tr>
      <tr>
        <td>Exit to the start screen.</td>
        <td>
          <b>START</b>
        </td>
        <td>HOME</td>
      </tr>
      <tr>
        <td>Move the marble selection.</td>
        <td>D-pad</td>
        <td>ARROW keys</td>
      </tr>
      <tr>
        <td>Break the selected marbles.</td>
        <td>
          <b>A</b>
        </td>
        <td>
          <b>A</b>
        </td>
      </tr>
      <tr>
        <td>Toggle full-screen mode.</td>
        <td>
           
        </td>
        <td>ALT+ENTER</td>
      </tr>
    </table>
  </div>

  <a name="ID2EDG"></a><h1 class="heading">Code Walkthrough</h1><div id="ID2EDG" class="hxnx1">
    
    <p>Marblets was created using the standard XNA Game Studio templates (from the <b>File | New | Project</b> dialog box). Program.cs contains the standard XNA Game Studio application launch code.</p>

    <a name="ID2EQG"></a><h2 class="subHeading">MarbletsGame.cs</h2><div id="ID2EQG" class="hxnx2">
      
      <p>MarbletsGame is a fairly standard implementation of the main game template created with a new project. MarbletsGame consists of three components, which are added to the game in the constructor.</p>

      <img src="ComponentClasses.png">

      <p>The GameScreen and TitleScreen components handle all of the game's rendering. Their constructors specify the backdrop and background music that will be used when those components are enabled and made visible. InputHelper provides button press information from the gamepad and keyboard. These three components are created in the game constructor and added to the components collection.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>mainGame = new GameScreen( this, "play_frame", SoundEntry.MusicGame );
mainGame.Enabled = false;
mainGame.Visible = false;
this.Components.Add( mainGame );

splashScreen = new TitleScreen( this, "title_frame", SoundEntry.MusicTitle );
splashScreen.Enabled = true;
splashScreen.Visible = true;
this.Components.Add( splashScreen );

inputHelper = new InputHelper( this );
inputHelper.UpdateOrder = int.MinValue;
this.Components.Add( inputHelper );</pre></pre></td></tr></table></span></div>

      <p>At game startup, the game framework calls the <b>Initialize</b> method. Since all of the Marblet code is handled in the components, you just need to call the base class and they will be initialized.</p>
    </div>

    <a name="ID2EEH"></a><h2 class="subHeading">Screen.cs</h2><div id="ID2EEH" class="hxnx2">
      
      <p>Screen is a <b>DrawableGameComponent</b>, which means that its update method will be called every tick when the component is enabled, and its <b>Draw</b> method will be called every tick when the component is visible. Marblets does not directly use Screen, but two classes inherit from Screen to provide the title screen and the main game screen.</p>

      <p>The Screen class provides two useful features.</p>
      <ul>
        <li>It automatically renders a backdrop, set when the screen is constructed.</li>
        <li>It automatically plays background music that is stopped and started automatically as the screen is made visible and enabled.</li>
      </ul>
    </div>

    <a name="ID2EZH"></a><h2 class="subHeading">TitleScreen.cs</h2><div id="ID2EZH" class="hxnx2">
      
      <p>TitleScreen adds two things to the normal screen class.</p>
      <ul>
        <li>The <code>Update</code> method determines whether <b>A</b> or <b>B</b> has been pressed, and, if so, transitions to the 2D game.</li>
        <li>The <code>Draw</code> method uses the font class to render the high score table.</li>
      </ul>

      <img src="titlescreen.png">
    </div>

    <a name="ID2EVAAC"></a><h2 class="subHeading">GameScreen.cs</h2><div id="ID2EVAAC" class="hxnx2">
      
      <p>GameScreen is also a simple implementation. Its constructor creates an instance of GameBoard. All game logic and rendering happens in GameBoard. The other changes are simple.</p>
      <ul>
        <li>The <code>Update</code> method calls <code>gameboard.Update</code> to update the gameboard.</li>
        <li>The <code>Draw</code> method calls <code>gameboard.Draw</code> to render the board and write the score. If the game has ended, the Game Over overlay is displayed.</li>
      </ul>
    </div>

    <a name="ID2ENBAC"></a><h2 class="subHeading">GameBoard.cs</h2><div id="ID2ENBAC" class="hxnx2">
      
      <p>The GameBoard class implements all game logic.  You can override this class to provide new game modes.</p>
      <p>The gameboard is stored as a 2D array of Marbles. If there is no marble in a slot, the array entry for that marble is <b>null</b>.</p>
      <p>The <code>Update</code> code in GameBoard performs three different actions depending on the state of the breaking animation:</p>
      <ul>
        <li>If the breaking animation is active, it floats and slowly fades out the score.</li>
        <li>If the breaking animation is complete, it moves the marbles down and to the right to fill in the gaps.</li>
        <li>When neither of the above is occurring, it accepts user input.</li>
      </ul>

      <p>Searching for a matching set of marbles is handled with a recursive routine that starts at the cursor and marks each matching marble as selected. When the recursion runs out of marbles of the same color that are not already selected, then it knows it has found everything. A running count easily allows the game logic to know if there are more than two marbles. You can see this logic in the <code>selectMarble</code>, <code>selectSurrounding</code>, and <code>matchColor</code> methods.</p>

      <p>The game is over when there are no marbles on the board that have a marble of the same color adjacent to them. This does not require any recursion because as soon as two marbles of the same color are found, you can stop, because there is at least one valid move left. The implementation is in the <code>isGameOver</code> method.</p>

      <p>After marbles are broken the cursor needs to move to a valid square. The marbles are searched in a spiral starting from the current position and moving down and to the right. This is implemented in <code>findCursorPosition</code>.</p>

      <p>Finally, the <code>Draw</code> overload iterates through the marble array and calls the <code>Draw</code> method on each marble, then draws the cursor and the current score for the and selected marbles.</p>

      <img src="2d.png">
    </div>

    <a name="ID2EEDAC"></a><h2 class="subHeading">Marble.cs</h2><div id="ID2EEDAC" class="hxnx2">
      

      <p>There is no game logic in Marble.cs; its purpose is to separate out the drawing code for the marbles from the game board.</p>
      <p>The marbles are rendered as sprites. There is a single monochrome sprite that is tinted using the color overload in SpriteBatch.Draw. Selection is indicated by cross fading between two different sprites, and breaking is done with a twelve frame animation. The animation is in the alpha channel of the graphic, so make sure that channel is visible when you edit the graphic.</p>
      <img src="2dselect.png">
      <img src="2dbreak.png">

      <p>To indicate selection, the marble scale is varied to make the marble pulse in size. Bursting is a faster increase in size as well as an increase in alpha to make the marble fade.</p>

    </div>

    <a name="ID2EVDAC"></a><h2 class="subHeading">RelativeSprite.cs</h2><div id="ID2EVDAC" class="hxnx2">
      
      <p>One game requirement was to work on multiple resolution screens, including resizable windows. The art was designed to work in both 4:3 and 16:9 aspect ratios; all of the main gameplay is within the center of the 16:9 backdrop. This allows the sides to simply be clipped when the window shrinks. On Xbox, sizing and letterboxing is handled by the hardware scaler, but on Windows it must be done in code.</p>

      <p>Window resizing is handled by shrinking and moving the sprites based on the window size. Game logic always assumes 1280×720, but whenever a <b>SpriteBatch.Draw</b> method is called, the parameters are scaled appropriately for the new window size.  <code>RelativeSprite</code> overrides <b>SpriteBatch</b> to handle this. An additional method is added to deal with the resizing. Whenever the screen is resized, this code is run and calculates an x offset for all the sprites and a scaling factor that can be passed into the <b>sprite.Draw</b> overload.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>public void Resize()
{

    // Heights are just scaled to fit the current window height.
    // Widths are scaled in proportion.
    // The x offset is calculated to force the images to center themselves no 
    // matter what the aspect ratio.
    // Left as right will be clipped as required.
    scale = (float)GraphicsDevice.Viewport.Height / (float)fullHeight;
    offset = (int)((GraphicsDevice.Viewport.Width - fullWidth * scale) / 2);
}</pre></pre></td></tr></table></span></div>

      <p>Translating the coordinates uses simple math, and then the base <b>SpriteBatch</b> is called to do the drawing.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>public new void Draw( Texture2D texture, Vector2 position, Rectangle? source, 
                     Color color )
{
    // Ensure that Resize has been called at least once before we try to draw.
    Debug.Assert(scale != 0, "Resize has not been called on RelativeSprite");

    // Scale and move the sprite based on the current screen size.
    base.Draw( texture, new Vector2( (int)((position.X * scale) + offset), 
              (int)(position.Y * scale)), source, color, 0, Vector2.Zero, scale,
              SpriteEffects.None, 0 );
}</pre></pre></td></tr></table></span></div>

    </div>

    <a name="ID2EUEAC"></a><h2 class="subHeading">InputHelper.cs, GamePadHelper.cs, and GamePads.cs</h2><div id="ID2EUEAC" class="hxnx2">
      
      <p>The GamePad code in Spacewar is similar to that in Marblets. Unlike Windows Forms programming, XNA Game Studio does not provide callback events for the keyboard, mouse, or gamepad. Instead, the model is a faster polling method in which the game queries the current state of input devices. Keyboards and buttons indicate whether they are currently up or down, while thumbsticks and the mouse indicate their current values.</p>

      <p>These three classes are called automatically on every tick of the game loop because they implement a <b>GameComponent</b>. During each tick, they look at the current state of the gamepad and the keyboard and check to see whether it has changed since the last time it was called. When the components detect that a button has been pressed and then released, they set a flag so that the game can take the appropriate action. The keyboard control is implemented by mapping certain keys to the A, B, X, Y and direction controls. The main game responds to defined actions, which can be generated by either the keyboard or gamepad.</p>

      <p>The pseudocode looks something like:</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>if (button is down) then set buttonDownFlag
if (key is down) then set keyDownFlag

if ((button is up and buttonDownFlag is set) OR (key is up and keyDownFlag is set)) then Button was clicked.</pre></pre></td></tr></table></span></div>

      <p>This check is executed for each button and key press, with the use of some helper functions to avoid repetitive code.</p>
    </div>

    <a name="ID2EKFAC"></a><h2 class="subHeading">Settings.cs</h2><div id="ID2EKFAC" class="hxnx2">
      
      <p>Settings is a simple class that is deserialized when the game is first run. The only thing stored in the file for Marblets is the marble colors.</p>
    </div>

    <a name="ID2ERFAC"></a><h2 class="subHeading">Font.cs</h2><div id="ID2ERFAC" class="hxnx2">
      
      <p>You might recognize the basis of this class from Spacewar. One change that has been made is to require users to pass in a <b>SpriteBatch</b> rather than using an internally stored one. This allows for a more efficient rendering pass by including test rendering in the same <b>SpriteBatch</b> that is being used for other operations.</p>

      <p>Marblets has two font files. Since all that is required for this game are the numbers 0–9, that is all that the font provides. The files were generated by an artist using PhotoShop.</p>

      <img src="fonts.png">

      <p>Each font file has a few parameters associated with it to enable proper rendering. These numbers are hard-coded in the constructor for the font class.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>private static FontInfo[] fontInfo = new FontInfo[] 
{
    new FontInfo( "numbers_small", "1234567890,", 10, 32, 18, 32 ),
    new FontInfo( "numbers_large", "1234567890,", 20, 64, 30, 64 ),
};</pre></pre></td></tr></table></span></div>

      <p>Once the string to be rendered is passed in, the portion of the texture for that character is located.  <b>SpriteBatch</b> renders the character, and the draw position is moved to the next character.</p>

      <p>While this technique allows only for monospace fonts, the rendering code contains a workaround that halves the width of the ',' and ':' characters to make the output look more pleasing to the eye.</p>
    </div>

    <a name="ID2ERGAC"></a><h2 class="subHeading">Sound.cs</h2><div id="ID2ERGAC" class="hxnx2">
      
      <p>The Sound class takes the string-based cue names and wraps a strongly named enumeration around them. This results in easier debugging and cleaner looking code. Initialization and shutdown are implementations of the standard XACT startup and shutdown code.</p>
    </div>

  </div>

  <a name="extending"></a><h1 class="heading">Extending Marblets</h1><div id="extending" class="hxnx1">
    
    <a name="ID2E5GAC"></a><h2 class="subHeading">Adding Mouse Support</h2><div id="ID2E5GAC" class="hxnx2">
      
      <p>The code to implement mouse support is already included in GameBoard.cs. Simply uncomment the first line after the file header.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>//#define mouse  // Uncomment to enable mouse - see mouse tutorial.</pre></pre></td></tr></table></span></div>

      <p>Adding mouse support to Marblets is quite simple. There are just a few steps to take.</p>
      <ul>
        <li>Detect mouse movement and show the cursor. You don't want the mouse to be visible unless the user needs it. This means turning off the mouse when the user chooses to use the keyboard or gamepad. All three input methods work well with each other.</li>
        <li>Check whether the mouse is over a marble, and move the cursor if it is.</li>
        <li>Check whether the mouse button has been pressed over a valid game move, and break the marble if it has.</li>
      </ul>

      <p>Most of the logic for cursor and game piece checking is already implemented in GameBoard.cs.  Moving the cursor with the mouse is added in the moveCursor method.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>//Show the mouse if it has moved.
MouseState mouse = Mouse.GetState();
if (mouse.X != lastMouseX &amp;&amp; mouse.Y != lastMouseY)
{
    Game.IsMouseVisible = true;
}

//If the mouse is visible, track the cursor with the mouse.
if (Game.IsMouseVisible)
{
    //Find which marble is under the cursor.
    cursorMovedWithMouse = moveCursorWithMouse( mouse.X, mouse.Y );
    lastMouseX = mouse.X;
    lastMouseY = mouse.Y;
}</pre></pre></td></tr></table></span></div>

      <p>You don't want the cursor to move if the mouse is not over a marble, or if the mouse is moving within the already selected marble. You also need to consider resizing the screen to determine where the marbles are. Notice the similarity between the math here and in RelativeSprite.</p>
      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>private bool moveCursorWithMouse( int x, int y )
{
    bool clickedOnMarble = false;

    double scale = (float)GraphicsDevice.Viewport.Height / 720.0;
    double offset = (int)((GraphicsDevice.Viewport.Width - 1280 * scale) / 2);

    int boardX = (int)((((x-offset) / scale) - LeftEdge) / Marble.Width);
    int boardY = (int)(((y/scale) - TopEdge ) / Marble.Height);
    if (boardX &gt;=0 &amp;&amp; boardX &lt; Width &amp;&amp; boardY &gt;= 0 &amp;&amp; boardY &lt; Height &amp;&amp; 
        Marbles[boardX, boardY] != null)
    {
        //Don't move and play the sound if the mouse is moving within the marble.
        if (cursorX != boardX || cursorY != boardY)
        {
            cursorX = boardX;
            cursorY = boardY;
            clickedOnMarble = true;
        }
    }

    return clickedOnMarble;
}</pre></pre></td></tr></table></span></div>

      <p>In the <code>BreakMarbles</code> method, the mouse button is checked for a state change.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>bool buttonClicked=false;
MouseState mouse = Mouse.GetState();
if (mouse.LeftButton == ButtonState.Pressed)
{
    buttonDown = true;
}


if (buttonDown &amp;&amp; mouse.LeftButton == ButtonState.Released)
{
    buttonDown = false;
    buttonClicked = true;
}</pre></pre></td></tr></table></span></div>
    </div>

    <a name="ID2E5IAC"></a><h2 class="subHeading">Adding a New Game Mode</h2><div id="ID2E5IAC" class="hxnx2">
      
      <p>The code to implement one alternative game mode is already included in GameScreen.cs. Simply uncomment the first line after the file header.</p>
      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>//#define TutorialVersion // Uncomment this line to play the tutorial version.</pre></pre></td></tr></table></span></div>

      <p>If you have played the original Bubblets game, then you know there are many different modes of play. This tutorial shows you how easy it is to add one of the variations. In this version, a new set of marbles will drop in every so often. All the code needed is in TutorialGameBoard.cs, which inherits the original GameBoard.cs.</p>

      <p>You'll need to override the <code>Update</code> method and call the base class to handle the normal game updates. You'll also need to check a timer to see if enough time has passed. If enough time has passed, attempt to drop a full row of marbles.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>// If it's time to add marbles, then add a row.
if (gameTime.TotalGameTime.TotalSeconds &gt; nextDropTime)
{
    AttemptDrop();
    nextDropTime = gameTime.TotalGameTime.TotalSeconds + dropInterval;
}</pre></pre></td></tr></table></span></div>

      <p>The <code>AttemptDrop</code> method adds a new marble to each column that has at least one space in it.</p>
    </div>

    <a name="ID2E1JAC"></a><h2 class="subHeading">Other Modifications to Try</h2><div id="ID2E1JAC" class="hxnx2">
      
      <p>Marblets is a starter kit—its purpose is to give you a fairly full featured game as an example, and then encourage you to make changes and reinvent the game. XNA Game Studio makes this very easy to do. Here are some ideas for further changes.</p>
      <ul>
        <li>Change the sprites to different graphics or models.</li>
        <li>Add a 3D mode.</li>
        <li>Animate the sprite so that it deforms and slides.</li>
        <li>Add more game modes—maybe a timed mode, or a mode where the game ends when the board fills back up.</li>
        <li>Add an options screen to select between all of the game modes that you created.</li>
      </ul>
    </div>
  </div>

</div><div class="footer" id="footer"><p>© 2008 Microsoft Corporation. All rights reserved.<br>Send feedback to <a href="mailto:xnags@microsoft.com?subject=Documentation Feedback: Marblets Starter Kit">xnags@microsoft.com</a>.</p></div></div></body></html>